#include "db_api_.h"

#ifndef _WIN32
#include <ctype.h>
#endif

char * const ignore_dir_list[] = 
{
	//特别注意，这个目录列表必须都是ASCII字符串，子目录也必须是ASCII目录名
	WAVEROOT,
	DBROOT,
	SDROOT"\\dict",
	SDROOT"\\System Volume Information",
	0,
};

FRESULT db_ffopen(FIL ** fp, const char* path, unsigned char mode)
{
	FRESULT res;

	assert(*fp == 0);
	*fp = (FIL*)OAL_calloc(1, sizeof(FIL));
	if(0==*fp)
	{
		return FR_INT_ERR;
	}
	
	res = f_open(*fp, path, mode);

	if(FR_OK != res)
	{
		OAL_free(*fp);
		*fp = 0;
	}

	return res;
}

FRESULT db_ffclose(FIL ** fp)
{
	if(*fp)
	{
		FRESULT res = f_close(*fp);
		OAL_free(*fp); 
		*fp = 0;
		return res;
	}
	return FR_OK;
}


int is_ignore_dir(const char * dir)	// 返回0=不在忽略目录列表
{
	int i;
	for(i=0; ignore_dir_list[i]; i++)
	{
		if(dircmp(ignore_dir_list[i], dir) == 0)
			return 1;
	}
	return 0;
}

int is_ignore_dirA(const char * dir, const char * ignore_dir[])
{
	int i;
	if(0 == ignore_dir)	return 0;
	for(i=0; ignore_dir[i]; i++)
	{
		if(dircmp(ignore_dir[i], dir) == 0)
			return 1;
	}
	return 0;
}

int is_mounted(void)
{
	if(hDB)
	{
		return hDB->cb_get_sd_status(0);
	}
	else
	{
		return 0;
	}
}

DWORD get_dir_size(const char * root)
{
	DWORD DirSize = 0;
	FRESULT fr;     /* Return value */
    DIR dj;         /* Directory object */
    FILINFO fno;    /* File information */

	fr = f_findfirst(&dj, &fno, root, "*");

	while(fr == FR_OK && fno.fname[0])
	{
		char path[MAXPATH];
		int tmp_len = strlen(root) + strlen("\\") + strlen(fno.fname);
   		if (tmp_len < MAXPATH)
		{
			strcpy(path, root);
			strcat(path, "\\");
			strcat(path, fno.fname);

			if((fno.fattrib & AM_DIR)
				&&(0 != strcmp(fno.fname, "."))
				&&(0 != strcmp(fno.fname, "..")))
			{
				DirSize += get_dir_size(path);
			}
			else if(fno.fattrib & AM_ARC)
			{
				unsigned long long size = fno.fsize;
				size = (size + hDB->sector_size - 1) / hDB->sector_size;
				DirSize += (DWORD)size;
			}
		}
		fr = f_findnext(&dj, &fno);	//Search for next item
		DB_SLP
    }

    f_closedir(&dj);
	return DirSize;
}

void clear_dir(const char * root)
{
	FRESULT fr;     /* Return value */
    DIR dj;         /* Directory object */
    FILINFO fno;    /* File information */

	fr = f_findfirst(&dj, &fno, root, "*");

	while(fr == FR_OK && fno.fname[0])
	{
		char path[MAXPATH];
		int tmp_len = strlen(root) + strlen("\\") + strlen(fno.fname);
   		if (tmp_len < MAXPATH)
		{
			strcpy(path, root);
			strcat(path, "\\");
			strcat(path, fno.fname);
	
			if((fno.fattrib & AM_DIR)
				&&(0 != strcmp(fno.fname, "."))
				&&(0 != strcmp(fno.fname, "..")))
			{
				clear_dir(path);
			}
			else if(fno.fattrib & AM_ARC)
			{
				f_unlink(path);
			}
		}
		fr = f_findnext(&dj, &fno);	//Search for next item
		DB_SLP
    }

    f_closedir(&dj);
}

int get_ignore_dir_size(void)
{
	int i;
	DWORD ndbsize = 0;
	for(i=1; ignore_dir_list[i]; i++)
	{
		ndbsize += get_dir_size(ignore_dir_list[i]);
	}
	return ndbsize;
}

DWORD get_free_clst(void)
{
	DWORD nclst = 0;
	DWORD ndbsize = 0;
	DWORD clust_size = 0;
	if(FR_OK == ext_get_free_(&nclst, &clust_size))
	{
		hDB->sector_size = clust_size * 512;
		ndbsize = get_ignore_dir_size();
		return nclst + ndbsize;
	}
	else
	{
		return 0;
	}
}

unsigned int sorthash(const char * fname)
{
	int i;
	int len;
	char name[MAXPATH];
	unsigned int ret;

	split_path(fname, 0, 0, name, 0);
	len = strlen(name);

	ret = 0;
	for(i=0; i<4 && i<len; i++)
	{
		unsigned char c = (unsigned char)tolower(fname[i]);
		ret |= c<<((3-i)*8);
	}
	return ret;
}

int db_is_file_exist(const char * path)
{
	FILINFO finfo;
	return f_stat(path, &finfo);
}

int is_archive(const char * path)//返回1=是可删除文件，0=不是可删除文件
{
	FILINFO finfo;
	if(f_stat(path, &finfo) == FR_OK)
	{
		if(finfo.fattrib == AM_ARC)
		{
			return 1;
		}
		else if (finfo.fattrib == (AM_ARC | AM_RDO))
		{
			return 2;
		}
	}
	return 0;
}

int file_type(const char * path)
{
	const char tab_ext[13][8]=
	{
		".txt",
		".bmp",
		".jpg",
		".jpeg",
		".mp3",
		".aac",
		".wma",
		".m4a",
		".flac",
		".ape",
		".wav",
		".ogg",
		".avi",
	};
	int i;
	char dir[MAXPATH] = { 0 };
	char ext[MAXPATH] = { 0 };
	split_path(path, dir, 0, 0, ext);

	for(i=0; i<13; i++)
	{
		if(dircmp(tab_ext[i],ext)==0)
		{
			switch(i)
			{
			case 0:		return MEDIA_HI_EBOOK | MEDIA_LO_TXT	;
			case 1:		return MEDIA_HI_IMAGE | MEDIA_LO_BMP	;
			case 2:		return MEDIA_HI_IMAGE | MEDIA_LO_JPG	;
			case 3:		return MEDIA_HI_IMAGE | MEDIA_LO_JPEG	;
			case 4:		return MEDIA_HI_AUDIO | MEDIA_LO_MP3	;
			case 5:		return MEDIA_HI_AUDIO | MEDIA_LO_AAC	;
			case 6:		return MEDIA_HI_AUDIO | MEDIA_LO_WMA	;
			case 7:		return MEDIA_HI_AUDIO | MEDIA_LO_M4A	;
			case 8:		return MEDIA_HI_AUDIO | MEDIA_LO_FLAC	;
			case 9:		return MEDIA_HI_AUDIO | MEDIA_LO_APE	;
			case 10:	return dircmp(dir, WAVEROOT) ? (MEDIA_HI_AUDIO | MEDIA_LO_WAV) : (MEDIA_HI_WAVE | MEDIA_LO_WAV);
			case 11:	return MEDIA_HI_AUDIO | MEDIA_LO_OGG	;
			case 12:	return MEDIA_HI_VIDEO | MEDIA_LO_AVI	;
			default:	return 0;
			}
		}
	}
	
	return 0;
}

void zip_space(char *s)
{
	int i;
	int len;
	
	if(s == 0)
		return;

	len = strlen(s);

	for(i=len-1; i>=0; i--)
	{
		if(s[i] == 0x20)
			s[i] = 0;
		else
			break;
	}
}

void split_path(const char* path, char* dir, char* fname, char* name, char* ext)
{
	int i;
	int start, end;
	int len;

	assert(path);
	len = strlen(path);
	assert(len < MAXPATH);

	if (dir)
	{
		dir[0] = 0;
		start = 0;
		end = 0;
		for (i = len - 1; i >= 0; i--)
		{
			if (path[i] == '/' || path[i] == '\\')
			{
				end = i;
				break;
			}
		}
		for (i = start; i < end; i++)
		{
			dir[i - start] = path[i];
		}
		dir[end - start] = 0;
	}

	if (fname)
	{
		fname[0] = 0;
		start = 0;
		end = len;
		for (i = len - 1; i >= 0; i--)
		{
			if (path[i] == '/' || path[i] == '\\')
			{
				start = i + 1;
				break;
			}
		}
		for (i = start; i < end; i++)
		{
			fname[i - start] = path[i];
		}
		fname[end - start] = 0;
	}

	if (name)
	{
		name[0] = 0;
		start = 0;
		end = len;
		for (i = len - 1; i >= 0; i--)
		{
			if (path[i] == '/' || path[i] == '\\')
			{
				start = i + 1;
				break;
			}
		}
		for (i = len - 1; i >= 0; i--)
		{
			if (path[i] == '.')
			{
				end = i;
				break;
			}
		}
		for (i = start; i < end; i++)
		{
			name[i - start] = path[i];
		}
		name[end - start] = 0;
	}

	if (ext)
	{
		ext[0] = 0;
		start = 0;
		end = 0;
		for (i = len - 1; i >= 0; i--)
		{
			if (path[i] == '/' || path[i] == '\\')
				break;

			if (path[i] == '.')
			{
				start = i;
				end = len;
				break;
			}
		}
		for (i = start; i < end; i++)
		{
			ext[i - start] = path[i];
		}
		ext[end - start] = 0;
	}
}

void split_path1(const char * path, char * dir, char * fname, char * name, char * ext)
{
	int i;
	int start,end;
	int len;
	char mask[MAXPATH] = { 0 };

	assert(path);
	len = strlen(path);
	assert(len < MAXPATH);

	for (i = 0; i < len; i++)
	{
		if(IsDBCS(DbCodePage))
		{
			if ((unsigned char)path[i] < 0x80)
			{
				mask[i] = 1;
			}
			else
			{
				i++;
			}
		}
		else
		{
			mask[i] = 1;
		}
	}

	if(dir)
	{
		dir[0] = 0;
		start = 0;
		end = 0;
		for(i=len-1; i>=0; i--)
		{
			if(mask[i] && (path[i] == '/' || path[i] == '\\'))
			{
				end = i;
				break;
			}
		}
		for(i=start; i<end; i++)
		{
			dir[i-start] = path[i];
		}
		dir[end-start] = 0;
	}

	if(fname)
	{
		fname[0] = 0;
		start = 0;
		end = len;
		for(i=len-1; i>=0; i--)
		{
			if(mask[i] && (path[i] == '/' || path[i] == '\\'))
			{
				start = i+1;
				break;
			}
		}
		for(i=start; i<end; i++)
		{
			fname[i-start] = path[i];
		}
		fname[end-start] = 0;
	}

	if(name)
	{
		name[0]=0;
		start = 0;
		end = len;
		for(i=len-1; i>=0; i--)
		{
			if(mask[i] && (path[i] == '/' || path[i] == '\\'))
			{
				start = i+1;
				break;
			}
		}
		for(i=len-1; i>=0; i--)
		{
			if(mask[i] && (path[i] == '.'))
			{
				end = i;
				break;
			}
		}
		for(i=start; i<end; i++)
		{
			name[i-start] = path[i];
		}
		name[end-start] = 0;
	}

	if(ext)
	{
		ext[0]=0;
		start = 0;
		end = 0;
		for(i=len-1; i>=0; i--)
		{
			if(mask[i] && (path[i] == '/' || path[i] == '\\'))
				break;

			if(mask[i] && (path[i] == '.'))
			{
				start = i;
				end = len;
				break;
			}
		}
		for(i=start; i<end; i++)
		{
			ext[i-start] = path[i];
		}
		ext[end-start] = 0;
	}
}

int dircmp(const char * path, const char * dir)
{
	unsigned int i;
	unsigned int len;
	
	if(path == 0 || dir == 0)
		return 1;

	len = strlen(dir);

	if(len == 0)
		return 1;
	if(strlen(path) != len)
		return 1;

	for(i=0; i<len; i++)
	{
		if((path[i]=='\\' || path[i] == '/') && (dir[i]=='\\' || dir[i] == '/'))
			continue;
		if(tolower(path[i]) != tolower(dir[i]))
			return tolower(path[i]) - tolower(dir[i]);
		if((unsigned char)path[i] > 0x80)
		{
			++i;
			if(path[i] != dir[i])
				return path[i] - dir[i];
		}
	}

	return 0;
}

void dir_to_utf8_(const unsigned char* fname, unsigned char* out, int len)
{
#if (defined WIN32) || (FF_LFN_UNICODE != 2)
	int name_len, out_len;
	int full;

	out[0] = 0;

	if (fname == 0)
		return;

	name_len = strlen((char*)fname);

	out_len = db_gb2312_to_utf8Ex(fname, name_len, (unsigned char*)out, len - 1, &full);

	if (full)
	{
		out[out_len] = '~';
		out[out_len + 1] = 0;
	}
	else
	{
		out[out_len] = 0;
	}
#else
	if (strlen((char*)fname) < len)
	{
		strcpy((char*)out, (char*)fname);
	}
	else
	{
		strncpy((char*)out, (char*)fname, len);
		out[len - 2] = '~';
		out[len - 1] = 0;
	}
#endif
}

void name_to_utf8_(const unsigned char * fname, unsigned char * out, int len)
{
#if (defined WIN32) || (FF_LFN_UNICODE != 2)
	char name[MAXPATH];
	char ext[MAXPATH];
	int name_len, ext_len, out_len;
	int full;

	out[0] = 0;

	if (fname == 0)
		return;

	split_path((char*)fname, 0, 0, name, ext);
	name_len = strlen(name);
	ext_len = strlen(ext);

	if (len - 1 <= ext_len + 1)
		return;

	out_len = db_gb2312_to_utf8Ex((const unsigned char*)name, name_len, (unsigned char*)out, len - 1 - (ext_len + 1), &full);

	if (full)
	{
		out[out_len] = '~';
		out[out_len + 1] = 0;
	}
	else
	{
		out[out_len] = 0;
	}

	strcat((char*)out, ext);
#else
	if (strlen((char*)fname) < len)
	{
		strcpy((char*)out, (char*)fname);
	}
	else
	{
		strncpy((char*)out, (char*)fname, len);
		out[len - 2] = '~';
		out[len - 1] = 0;
	}
#endif
}

void dir_to_utf8(const unsigned char * fname, unsigned char * out, int len)
{
#if (defined WIN32) && (defined UNICODE)
	wchar_t wstr[MAXPATH] = {0};
	char tmp[MAXPATH] = {0};
	MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)fname, -1, wstr, MAXPATH);
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, tmp, MAXPATH, NULL, FALSE);
	dir_to_utf8_((unsigned char*)tmp, out, len);
#else
	dir_to_utf8_(fname, out, len);
#endif
}

void name_to_utf8(const unsigned char * fname, unsigned char * out, int len)
{
#if (defined WIN32) && (defined UNICODE)
	wchar_t wstr[MAXPATH] = {0};
	char tmp[MAXPATH] = {0};
	MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)fname, -1, wstr, MAXPATH);
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, tmp, MAXPATH, NULL, FALSE);
	name_to_utf8_((unsigned char*)tmp, out, len);
#else
	name_to_utf8_(fname, out, len);
#endif
}

int id3_to_utf8(ID3FRAMEBODY * body, unsigned char * out_buff, int out_len)
{
//	FrameCont_encode ��4��ֵ; 
//	0000 0000 ����֡���� ISO-8859-1 ���뷽ʽ�洢�� 
//	0000 0001 ����֡���� UTF-16LE   ���뷽ʽ�洢�� 
//	0000 0010 ����֡���� UTF-16BE   ���뷽ʽ�洢�� 
//	0000 0011 ����֡���� UTF-8      ���뷽ʽ�洢��[ֻ��ID3V2.4��֧��UTF-8���뷽ʽ] 

	int len = body->len;
	int utf8_len = 0;

	if(len == 0)//û����
	{
		out_buff[0] = 0;
		return 0;
	}

	switch(body->FrameCont_Encode)
	{
	case 0:
		utf8_len = ISO_8859_1_to_utf8(body->FrameCont, len, out_buff, out_len);
		out_buff[utf8_len] = 0;
		break;

	case 1:
		if (body->FrameCont[0] == 0xFE)
		{
			utf8_len = UTF_16BE_to_utf8(body->FrameCont, len, out_buff, out_len);
		}
		else
		{
			utf8_len = UTF_16LE_to_utf8(body->FrameCont, len, out_buff, out_len);
		}
		out_buff[utf8_len] = 0;
		break;

	case 2:
		if(body->FrameCont[0] == 0xFF)
		{
			utf8_len = UTF_16LE_to_utf8(body->FrameCont, len, out_buff, out_len);
		}
		else
		{
			utf8_len = UTF_16BE_to_utf8(body->FrameCont, len, out_buff, out_len);
		}
		out_buff[utf8_len] = 0;
		break;

	case 3:
		if(len >= 3)
		{
			if(body->FrameCont[0] == 0xEF && body->FrameCont[1] == 0xBB && body->FrameCont[2] == 0xBF)
			{
				if(strlen((char *)&body->FrameCont[3]) >= (unsigned int)out_len)
					body->FrameCont[3+out_len-1] = 0;
				strcpy((char *)out_buff, (char *)&body->FrameCont[3]);
				break;
			}
		}
		if (strlen((char*)body->FrameCont) >= (unsigned int)out_len)
		{
			if ((body->FrameCont[out_len - 1] & 0xc0) != 0x80)
			{
				body->FrameCont[out_len - 1] = 0;
			}
			else if ((body->FrameCont[out_len - 2] & 0xc0) != 0x80)
			{
				body->FrameCont[out_len - 2] = 0;
			}
			else
			{
				assert((body->FrameCont[out_len - 3] & 0xc0) != 0x80);
				body->FrameCont[out_len - 3] = 0;
			}
		}
		strcpy((char *)out_buff, (char *)body->FrameCont);
		break;

	default:
		assert(0);
		if(strlen((char *)body->FrameCont) >= (unsigned int)out_len)
			body->FrameCont[out_len-1] = 0;
		strcpy((char *)out_buff, (char *)body->FrameCont);
		break;
	}

	zip_space((char*)out_buff);

	return 0;
}
